import axios from 'axios'
// 1.引入vue
import Vue from 'vue'
// 2.新创建一个vue实例
const nVue = new Vue()
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken, getRefToken, getTime, setToken, setRefreshToken, setTime, removeToken, removeRefToken, removeTime, removeUser } from '@/utils/auth'
import {} from '@/store/modules/user'
import router from '../router'

/* 是否有请求正在刷新token*/
window.isRefreshing = false
// 是否挂载
window.refFlag = false
/* 被挂起的请求数组*/
let refreshSubscribers = []

/* 获取刷新token请求的token*/
function getRefreshToken() {
  return getRefToken()
}

/* push所有请求到数组中*/
function subscribeTokenRefresh(cb) {
  refreshSubscribers.push(cb)
}

/* 刷新请求（refreshSubscribers数组中的请求得到新的token之后会自执行，用新的token去请求数据）*/
function onRrefreshed(token) {
  refreshSubscribers.map(cb => cb(token))
}
/* 判断token是否过期*/
function isTokenExpired() {
  /* 从localStorage中取出token过期时间,假如时间为3600s*/
  const reTime = getTime()
  const expiredTime = reTime
  /* 获取本地时间*/
  let nowTime = new Date().getTime()
  /* 校验本地时间*/
  nowTime = expiredTime - nowTime

  const diffTime = parseInt((nowTime % (1000 * 60 * 60)) / (1000 * 60))
  // console.log(diffTime);
  /* 如果 < 2分钟，则说明即将过期*/
  return diffTime < 2
}

// create an axios instance
const service = axios.create({
  transformRequest: [function(data) {
    // 将数据转换为表单数据
    let ret = ''
    for (const it in data) {
      if (data[it] != null) {
        ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
      }
    }
    return ret
  }],
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})

// request interceptor
service.interceptors.request.use(
  config => {
    // do something before request is sent
    config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    if (store.getters.token) {
      // let each request carry token
      // ['X-Token'] is a custom headers key
      // please modify it according to the actual situation

      if (config.url.indexOf('/sysUser/refreshToken.json' || '/sysUser/login.json') !== -1) {
        config.headers['Authorization'] = ''
      } else {
        config.headers['Authorization'] = 'Bearer ' + getToken()
      }

      // console.log(config.url.indexOf('/api/refreshToken.json'))
      /* 判断token是否将要过期*/
      if (isTokenExpired()) {
        /* 判断是否正在刷新*/
        if (!window.isRefreshing) {
          /* 将刷新token的标志置为true*/
          window.isRefreshing = true
          /* 发起刷新token的请求*/
          //  alert("token")
          post('/sysUser/refreshToken.json', { refreshToken: getRefreshToken() }).then(response => {
            // console.log(res);
            /* 将标志置为false*/
            window.isRefreshing = false
            /* 成功刷新token*/
            config.headers.Authorization = 'Bearer ' + response.access_token
            // config.headers.common['Authorization'] = 'Bearer '+res.access_token;
            /* 更新token*/
            const refTime = new Date().getTime() + response.expires_in * 1000 * 1000 / 1000

            setToken(response.access_token)
            setRefreshToken(response.refresh_token)
            setTime(refTime)

            // console.log(refTime)
            store.commit('user/SET_TOKEN', response.access_token)
            store.commit('user/SET_TIME', refTime)
            store.commit('user/SET_REFTOKEN', response.refresh_token)
            console.log(refreshSubscribers)

            /* 执行数组里的函数,重新发起被挂起的请求*/
            window.refFlag = true
            onRrefreshed(response.access_token)
            /* 执行onRefreshed函数后清空数组中保存的请求*/
            refreshSubscribers = []
          }).catch(err => {
            //  console.log(err);
            removeToken()
            removeRefToken()
            removeTime()
            removeUser()
            router.push({ path: '/login' })
          })
        }
        /* 把请求(token)=>{....}都push到一个数组中*/
        /*    let retry= new Promise((resolve, reject) => {
          /!*(token) => {...}这个函数就是回调函数*!/
          subscribeTokenRefresh((token) => {
            config.headers.Authorization = 'Bearer ' + token;
            // config.headers.common['Authorization'] = 'Bearer '+token;
            /!*将请求挂起*!/
            resolve(config)
          })
        })
        return retry*/
      }
    } else {
      if (config.url.indexOf('/sysUser/login.json') !== -1) {
        config.headers['Authorization'] = ''
      }
    }
    return config
  },
  error => {
    // do something with request error
  //  console.log(error) // for debug
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  /**
   * If you want to get http information such as headers or status
   * Please return  response => response
  */

  /**
   * Determine the request status by custom code
   * Here is just an example
   * You can also judge the status by HTTP Status Code
   */
  response => {
    // console.log(response);
    if (response.config.responseType == 'blob') {
      downloadFile(response.data)
      return
    }

    const res = response.data
    console.log(response)
    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 0) {
      nVue.$message({
        message: res.info || 'Error',
        type: 'error',
        duration: 3 * 1000
      })

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
          confirmButtonText: 'Re-Login',
          cancelButtonText: 'Cancel',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
      }
      return Promise.reject(new Error(res.info || 'Error'))
    } else {
      return res.data
    }
  },
  error => {
    const config = error.response.config
    if (error.response.status == 401) {
      // 返回 401 清除token信息并跳转到登录页面
      /* 把请求(token)=>{....}都push到一个数组中*/
      const retry = new Promise((resolve, reject) => {
        /* (token) => {...}这个函数就是回调函数*/
        subscribeTokenRefresh((token) => {
          config.baseURL = '' // url已经带上了/api，避免出现/api/api的情况
          config.headers.Authorization = 'Bearer ' + token
          // config.headers.common['Authorization'] = 'Bearer '+token;
          /* 将请求挂起*/
          resolve(service(config))
        })
      })
      return retry
    } else {
      console.log('err' + error) // for debug
      nVue.$message({
        message: error.message,
        type: 'error',
        duration: 3 * 1000
      })
      return Promise.reject(error)
    }
  }
)

const get = function(url, data) {
  let params = ''
  for (const key in data) {
    params += key + '=' + data[key] + '&'
  }
  return service({
    url: url + '?' + params,
    method: 'get'
  })
}
const downloadFile = function(data) {
  if (!data) {
    return
  }
  const url = window.URL.createObjectURL(new Blob([data]))
  const link = document.createElement('a')
  link.style.display = 'none'
  link.href = url
  link.setAttribute('download', 'excel.xlsx')

  document.body.appendChild(link)
  link.click()
}
const download = function(url, data) {
  let params = ''
  for (const key in data) {
    params += key + '=' + data[key] + '&'
  }
  return service({
    url: url + '?' + params,
    method: 'get',
    responseType: 'blob'
  })
}

const post = function(url, data) {
  return service({
    url: url,
    method: 'post',
    data
  })
}
const dele = function(url, data) {
  return service({
    url: url,
    method: 'delete',
    data
  })
}
const put = function(url, data) {
  return service({
    url: url,
    method: 'put',
    data
  })
}

const upload = function(url, data) {
  const config = {
    headers: { 'Content-Type': 'multipart/form-data' }
  } // 添加请求头
  return axios.post(url, data, config)
}
export { get, post, download, upload, put,dele }
export default service
